/*
 * printer.c
 *
 *  Created on: Mar 13, 2012
 *      Author: our_beastie
 */


#include "printer.h"
#include <malloc.h>
#include <stdlib.h>
#include "cpu.h"

void printInternal(Printer p, PrinterRequest pr);
void printStatus(CPU cpu);
char * getProcessTypeString(enum ProcessType process_type);
char * getProcessStateString(enum PCBState process_state);

PrinterRequest newPrinterRequest(enum InterruptRequestType irt,
		enum SystemCallRequestType scrt, int pid, int pstate) {
	PrinterRequest pr = (PrinterRequest) malloc(sizeof(PrinterRequestStr));
	pr->irt = irt;
	pr->scrt = scrt;
	pr->pid = pid;
	pr->pstate = pstate;

	return pr;
}

void destroyPrinterRequest(PrinterRequest pr) {
	free(pr);
}

Printer newPrinter(CPU_PRNTR cpu) {
	Printer printer = (Printer) malloc(sizeof(PrinterStr));
	printer->cpu = cpu;
	return printer;
}

void print(Printer p, PrinterRequest pr) {
	printInternal(p, pr);
	return;
}

void printInternal(Printer p, PrinterRequest pr) {
	if (pr->irt == NULL_INT) { //process system call
		switch (pr->scrt) {
		case IO_CALL:
			printf("Process %d (Calculator) made a system call to device 2 (IO).\n", pr->pid);
			break;
		case KEYBOARD_CALL:
			printf("Process %d (UI) made a system call to device 1 (Keyboard).\n", pr->pid);
			break;
		case PRODUCER_CALL:
			if (pr->pstate != BLOCKED) {
				printf("Process %d (Producer) incremented memory location 0.\n", pr->pid);
			} else {
				printf("Process %d (Producer) attempted to increment memory location 0.\n", pr->pid);
			}
			break;
		case CONSUMER_CALL:
			if (pr->pstate != BLOCKED) {
				printf("Process %d (Consumer) decremented memory location 0.\n", pr->pid);
			} else {
				printf("Process %d (Consumer) attempted to decrement memory location 0.\n", pr->pid);
			}
			break;
		}
	} else { //process interrupt
		switch(pr->irt) {
		case TIMER_INT:
			printf("Device 0 (System Timer) produced an interrupt\n");
			break;
		case KEYBOARD_INT:
			printf("Device 1 (Keyboard) produced an interrupt\n");
			break;
		case IO_INT:
			printf("Device 2 (IO) produced an interrupt\n");
			break;
		case PROD_INT:
			printf("Process %d (Producer) incremented memory location 0.\n", pr->pid);
			break;
		case CONS_INT:
			printf("Process %d (Consumer) decremented memory location 0.\n", pr->pid);
			break;
		}
	}
	printStatus((CPU) p->cpu);
	destroyPrinterRequest(pr);
	return;

}

void printStatus(CPU cpu) {

	char* process;
	char* state;
	int i;
	if (cpu->sched->scheduler_type == LOTTERY) {
		printf("Scheduler: Lottery scheduling, next running process is unknown.\n");
	} else {
		process = getProcessTypeString(getNextProcess(cpu->sched)->process_type);
		printf("Scheduler: Running process %d (%s) next.\n", getNextProcess(cpu->sched)->pcb->process_id, process);
	}

	i = 0;
	for (i = 0; i < cpu->num_processes; i++) {
		process = getProcessTypeString(cpu->process[i]->process_type);
		state = getProcessStateString(cpu->process[i]->pcb->state);
		printf("Process %d (%s)'s state: %s\n", i, process, state);
	}
	printf("\n");
	fflush(stdout);
	return;
}

char * getProcessStateString(enum PCBState process_state) {
	char * result;

	switch (process_state) {
	case RUNNING:
		result = "RUNNING";
		break;
	case READY:
		result = "READY";
		break;
	case BLOCKED:
		result = "BLOCKED";
		break;
	case INTERRUPTED:
		result = "INTERRUPTED";
		break;
	}
	return result;
}

char * getProcessTypeString(enum ProcessType process_type) {
	char * result;

	switch (process_type) {
	case UI:
		result = "UI";
		break;
	case CALCULATOR:
		result = "Calculator";
		break;
	case PRODUCER:
		result = "Producer";
		break;
	case CONSUMER:
		result = "Consumer";
		break;
	}
	return result;
}

